package de.sendorian.app.forumArchive.dundjinni;


import static de.sendorian.app.forumArchive.matcher.ForumArchiveBuilderMatchers.*;
import static org.apache.commons.lang.StringEscapeUtils.*;
import static org.hamcrest.Matchers.*;

import java.text.ParseException;
import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hamcrest.Matcher;
import org.htmlparser.NodeFilter;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NotFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.SimpleNodeIterator;

import de.sendorian.app.forumArchive.Config;
import de.sendorian.app.forumArchive.domain.Topic;
import de.sendorian.app.forumArchive.domain.Topic.Type;
import de.sendorian.app.forumArchive.finder.TopicFinder;
import de.sendorian.app.forumArchive.renamer.ForbiddenCharsRenamer;
import de.sendorian.app.forumArchive.renamer.StringRenamer;

public class DundjinniTopicFinder extends TopicFinder {

	private static final String FORUM_PAGE_PARAM = "&PN=";

	private static final int MAX_FORUM_PAGES = 19;

	private StringRenamer renamer;

	public DundjinniTopicFinder() {
		this(any(Topic.class), false);
		renamer = new ForbiddenCharsRenamer();
	}


	public DundjinniTopicFinder(Matcher<Topic> matcher, boolean tryAgain) {
		super(matcher, not(anyOf(isAnnouncementOrStickyTopic(), isIgnorableTopic())), tryAgain);
		logger = Logger.getLogger(this.getClass().getName());
	}


	@Override
	protected String getTopicName(TagNode row) {
		NodeFilter tdFilter = new HasAttributeFilter("width", "41%");
		NodeList tdList = row.getChildren().extractAllNodesThatMatch(tdFilter);
		if (tdList.size() > 0) {
			NodeFilter linkFilter = new TagNameFilter("a");
			NodeList links = ((TagNode) tdList.elementAt(0)).getChildren()
			    .extractAllNodesThatMatch(linkFilter);
			if (links.size() > 0) {
				String text = ((TagNode) links.elementAt(0)).getFirstChild().getText();
				return stripForbiddenChars(unescapeHtml(text));
			}
		}
		return null;
	}

	private String stripForbiddenChars(String name) {
		return renamer.rename(name);
	}

	@Override
	protected String getTopicStarter(TagNode row) {
		NodeFilter tdFilter = new HasAttributeFilter("width", "15%");
		NodeList tdList = row.getChildren().extractAllNodesThatMatch(tdFilter);
		if (tdList.size() > 0) {
			NodeFilter linkFilter = new TagNameFilter("a");
			NodeList links = ((TagNode) tdList.elementAt(0)).getChildren()
			    .extractAllNodesThatMatch(linkFilter);
			if (links.size() > 0) {
				String text = ((TagNode) links.elementAt(0)).getFirstChild().getText();
				return unescapeHtml(text);
			}
		}
		return null;
	}


	@Override
	protected String getLink(TagNode row) {
		TagNode td = getLastColumn(row);
		if (td == null) {
			return null;
		}

		NodeFilter linkFilter = new AndFilter(new TagNameFilter("a"), new NotFilter(
		    new HasAttributeFilter("class", "smLink")));
		NodeList linkList = td.getChildren().extractAllNodesThatMatch(linkFilter);
		if (linkList.size() > 0) {
			return ((TagNode) linkList.elementAt(0)).getAttribute("href");
		}
		return null;
	}


	@Override
	protected Date getLastPost(TagNode row) {
		TagNode td = getLastColumn(row);
		if (td == null) {
			return null;
		}

		SimpleNodeIterator it = td.getChildren().elements();
		while (it.hasMoreNodes()) {
			String nodeText = it.nextNode().toHtml();
			if (!StringUtils.isWhitespace(nodeText)) {
				java.util.regex.Matcher matcher = Config.get().getDatePattern().matcher(nodeText);
				if (matcher.find()) {
					String date = matcher.group(1) + ' ' + matcher.group(2);
					try {
						return Config.get().getDateFormat().parse(date);
					} catch (ParseException e) {
						logger.error("Could not parse the date '" + date + "'");
					}
				}
			}
		}
		return null;
	}


	@Override
	protected Type getType(TagNode row) {
		NodeFilter imageFilter = new AndFilter(new TagNameFilter("img"), new HasAttributeFilter(
		    "alt"));
		NodeList imageList = row.getChildren().extractAllNodesThatMatch(imageFilter, true);
		if (imageList.size() > 0) {
			return Topic.Type.valueOfDetail(((TagNode) imageList.elementAt(0)).getAttribute("alt"));
		}
		return null;
	}


	@Override
	protected String getNextPage(String url, int actualPageNr) {
		// starting forum page has no page number appended.
		if (!url.contains(FORUM_PAGE_PARAM)) {
			// the first page is also referenced with page numbers 0 or 1
			return url + FORUM_PAGE_PARAM + "2";
		}

		int nextPageNr = actualPageNr + 1;
		if (nextPageNr <= MAX_FORUM_PAGES) {
			return url.substring(0, url.lastIndexOf('=') + 1) + nextPageNr;
		}
		return null;
	}


	private TagNode getLastColumn(TagNode row) {
		NodeList lastColumnList = row.getChildren().extractAllNodesThatMatch(
		    new HasAttributeFilter("class", "smText"));
		if (lastColumnList.size() > 0) {
			return (TagNode) lastColumnList.elementAt(0);
		}
		return null;
	}

}
